﻿/*----------------------------------------------------------------------------------------
*
*  Copyright 2019, Gao Hai Hui, <fromzeropoint@126.com>.  All rights reserved.
*  https://gitee.com/helloworldghh/xoskit.git
*  Use of this source code is governed by a MIT license
*  that can be found in the License file.
*
----------------------------------------------------------------------------------------*/
#include "../import/head.h"
#include "../global/head.h"
#include "../xos/head.h"
#include "time_impl.h"

/////////////////////////////////////////////////////////////////////////////////////////
// 
namespace xos
{
    ////////////////////////////////////////////////////////////////////////////////////
    // 

    static time_t g_t_time_zone_second_s = -1;
    static time_impl::POOL * pool_ptr = 0;

    ////////////////////////////////////////////////////////////////////////////////////
    //

    time_impl::time_impl()
    {
        g_t_time_zone_second_s = -1;
        init_data();
    }

    time_impl::~time_impl()
    {
        term();
    }

    ////////////////////////////////////////////////////////////////////////////////////
    // 

    int time_impl::get_addr( POOL *** pppPool, LIST *** pppList )
    {
        int ret = 0;
        if( pppPool )
        {
            *pppPool = &pool_ptr;
        }
        if( pppList )
        {
            *pppList = 0;
        }
        return ret;
    }

    int time_impl::cal_time_zone_second()
    {
        int ret = 0;

        if( -1 != g_t_time_zone_second_s )
        {
            return 0;
        }

        struct tm * pTm = 0, tm1 = { 0 }, tm2 = { 0 };
        time_t t = time( 0 );

        time_t t1 = 0;
        time_t t2 = 0;

        pTm = localtime( &t );
        memcpy( &tm1, pTm, sizeof( struct tm ) );

        pTm = gmtime( &t );
        memcpy( &tm2, pTm, sizeof( struct tm ) );

        t1 = mktime( &tm1 );
        t2 = mktime( &tm2 );

        g_t_time_zone_second_s = t1 - t2;

        return ret;
    }

    int time_impl::init_data()
    {
        int ret = 0;

        memset( &m_tmval, 0, sizeof( m_tmval ) );
        memset( &m_tm, 0, sizeof( m_tm ) );

        cal_time_zone_second();

        return ret;
    }

    int time_impl::init()
    {
        int nRet = 0;
        return nRet;
    }

    int time_impl::term()
    {
        int nRet = 0;
        init_data();
        return nRet;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 

    // 
    // 2018-01-30 05:05:30
    // 
    int time_impl::get_time_string_ymdhms( char * lpszTimeStr, int nSize, int * lpnRetLen )
    {
        int ret = 0;

        int len = strftime( lpszTimeStr, nSize, "%Y-%m-%d %H:%M:%S", &m_tm );
        if( lpnRetLen )
        {
            *lpnRetLen = len;
        }

        return ret;
    }

    // 
    // 2018-01-30
    // 
    int time_impl::get_time_string_ymd( char * lpszTimeStr, int nSize, int * lpnRetLen )
    {
        int ret = 0;

        int len = strftime( lpszTimeStr, nSize, "%Y-%m-%d", &m_tm );
        if( lpnRetLen )
        {
            *lpnRetLen = len;
        }

        return ret;
    }

    // 
    // 12:03:23
    // 
    int time_impl::get_time_string_hms( char * lpszTimeStr, int nSize, int * lpnRetLen )
    {
        int ret = 0;

        int len = strftime( lpszTimeStr, nSize, "%H:%M:%S", &m_tm );
        if( lpnRetLen )
        {
            *lpnRetLen = len;
        }

        return ret;
    }

    // Wed, 28 Aug 2019 03:48:08 GMT
    int time_impl::get_time_string_gmt( char * lpszTimeStr, int nSize, int * lpnRetLen )
    {
        int ret = 0;

        time_t lt = ( time_t )get_wall_time_s();
        struct tm * pTm = 0;
        pTm = gmtime( &lt );
        int len = ( int )strftime( lpszTimeStr, nSize, "%a, %d %b %Y %X GMT", pTm );
        if( lpnRetLen )
        {
            *lpnRetLen = len;
        }

        return ret;
    }

    int time_impl::get_time_name_ymdhms( char * lpszTimeStr, int nSize, int * lpnRetLen )
    {
        int ret = 0;

        int len = strftime( lpszTimeStr, nSize, "%Y%m%d%H%M%S", &m_tm );
        if( lpnRetLen )
        {
            *lpnRetLen = len;
        }

        return ret;
    }

    int time_impl::get_time_name_ymd( char * lpszTimeStr, int nSize, int * lpnRetLen )
    {
        int ret = 0;

        int len = strftime( lpszTimeStr, nSize, "%Y%m%d", &m_tm );
        if( lpnRetLen )
        {
            *lpnRetLen = len;
        }

        return ret;
    }

    int time_impl::get_time_name_hms( char * lpszTimeStr, int nSize, int * lpnRetLen )
    {
        int ret = 0;

        int len = strftime( lpszTimeStr, nSize, "%H%M%S", &m_tm );
        if( lpnRetLen )
        {
            *lpnRetLen = len;
        }

        return ret;
    }

    xos_i64 time_impl::get_wall_time_s()
    {
        xos_i64 ret = 0;

        ret = mktime( &m_tm );

        return ret;
    }

    int time_impl::get_milli_second()
    {
        int nRet = m_tmval.tv_usec / 1000;
        return nRet;
    }

    // 
    // get time details
    // 
    int time_impl::get_year()
    {
        int nRet = m_tm.tm_year + 1900;
        return nRet;
    }

    int time_impl::get_month()
    {
        int nRet = m_tm.tm_mon + 1;
        return nRet;
    }

    int time_impl::get_week()
    {
        int nRet = m_tm.tm_wday;
        return nRet;
    }

    int time_impl::get_day()
    {
        int nRet = m_tm.tm_mday;
        return nRet;
    }

    int time_impl::get_hour()
    {
        int nRet = m_tm.tm_hour;
        return nRet;
    }

    int time_impl::get_minute()
    {
        int nRet = m_tm.tm_min;
        return nRet;
    }

    int time_impl::get_second()
    {
        int nRet = m_tm.tm_sec;
        return nRet;
    }

    // 
    // update time
    // 
    int time_impl::get_time()
    {
        int nRet = 0;

        struct timeval tmval = { 0 };
        struct tm mtm = { 0 };

        gettimeofday( &tmval, 0 );
        memcpy( &mtm, localtime( &tmval.tv_sec ), sizeof( struct tm ) );

        memcpy( &m_tmval, &tmval, sizeof( struct timeval ) );
        memcpy( &m_tm, &mtm, sizeof( struct tm ) );

        return nRet;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 
    // set time details
    // 

    // 
    // 2018-01-30 05:05:30
    // 
    int time_impl::set_time_string_ymdhms( const char * lpszTimeStr )
    {
        int ret = 0;

        memset( &m_tmval, 0, sizeof( m_tmval ) );
        memset( &m_tm, 0, sizeof( m_tm ) );

        strptime( lpszTimeStr, "%Y-%m-%d %H:%M:%S", &m_tm );
        m_tmval.tv_sec = mktime( &m_tm );

        return ret;
    }

    // 
    // 2018-01-30
    // 
    int time_impl::set_time_string_ymd( const char * lpszTimeStr )
    {
        int ret = 0;

        memset( &m_tmval, 0, sizeof( m_tmval ) );
        memset( &m_tm, 0, sizeof( m_tm ) );

        strptime( lpszTimeStr, "%Y-%m-%d", &m_tm );
        m_tmval.tv_sec = mktime( &m_tm );

        return ret;
    }

    // 
    // Wed, 28 Aug 2019 03:48:08 GMT
    // 
    int time_impl::set_time_string_gmt( const char * lpszTimeStr )
    {
        int ret = 0;

        time_t t = 0;

        {
            struct tm tm_s = { 0 };
            strptime( lpszTimeStr, "%a, %d %b %Y %X GMT", &tm_s );
            t = mktime( &tm_s ) + g_t_time_zone_second_s;
        }
        set_wall_time_s( t );

        return ret;
    }

    int time_impl::set_time_name_ymdhms( const char * lpszTimeStr )
    {
        int ret = 0;

        memset( &m_tmval, 0, sizeof( m_tmval ) );
        memset( &m_tm, 0, sizeof( m_tm ) );

        strptime( lpszTimeStr, "%Y%m%d%H%M%S", &m_tm );
        m_tmval.tv_sec = mktime( &m_tm );

        return ret;
    }

    int time_impl::set_time_name_ymd( const char * lpszTimeStr )
    {
        int ret = 0;

        memset( &m_tmval, 0, sizeof( m_tmval ) );
        memset( &m_tm, 0, sizeof( m_tm ) );

        strptime( lpszTimeStr, "%Y%m%d", &m_tm );
        m_tmval.tv_sec = mktime( &m_tm );

        return ret;
    }

    int time_impl::set_wall_time_s( xos_i64 tm_s )
    {
        int ret = 0;

        memset( &m_tmval, 0, sizeof( m_tmval ) );
        memset( &m_tm, 0, sizeof( m_tm ) );

        m_tmval.tv_sec = tm_s;
        memcpy( &m_tm, localtime( &m_tmval.tv_sec ), sizeof( struct tm ) );

        return ret;
    }

    int time_impl::set_milli_second( int tm_ms )
    {
        int ret = 0;
        m_tmval.tv_usec = tm_ms;
        return ret;
    }

    int time_impl::set_year( int tm_y )
    {
        int ret = 0;
        m_tm.tm_year = tm_y - 1900;
        m_tmval.tv_sec = mktime( &m_tm );
        return ret;
    }

    int time_impl::set_month( int tm_m )
    {
        int ret = 0;
        m_tm.tm_mon = tm_m - 1;
        m_tmval.tv_sec = mktime( &m_tm );
        return ret;
    }

    int time_impl::set_day( int tm_d )
    {
        int ret = 0;
        m_tm.tm_mday = tm_d;
        m_tmval.tv_sec = mktime( &m_tm );
        return ret;
    }

    int time_impl::set_hour( int tm_h )
    {
        int ret = 0;
        m_tm.tm_hour = tm_h;
        m_tmval.tv_sec = mktime( &m_tm );
        return ret;
    }

    int time_impl::set_minute( int tm_m )
    {
        int ret = 0;
        m_tm.tm_min = tm_m;
        m_tmval.tv_sec = mktime( &m_tm );
        return ret;
    }

    int time_impl::set_second( int tm_s )
    {
        int ret = 0;
        m_tm.tm_sec = tm_s;
        m_tmval.tv_sec = mktime( &m_tm );
        return ret;
    }

    ////////////////////////////////////////////////////////////////////////////////////
    // 

    // 
    // calculate time difference. unit : 1 / 1000 second
    // 
    int time_impl::diffrent( i_time * pLastTime, xos_i64 * lpulDif )
    {
        int nRet = 0;

        time_impl * pImpl = static_cast< time_impl * >( pLastTime );

        if( !lpulDif || !pLastTime )
        {
            nRet = 1;
        }

        if( 0 == nRet )
        {
            xos_i64 l_s = ( int )( m_tmval.tv_sec - pImpl->m_tmval.tv_sec );
            xos_i64 l_us = ( int )( m_tmval.tv_usec - pImpl->m_tmval.tv_usec );

            *lpulDif = l_s * 1000 + l_us / 1000;
        }

        return nRet;
    }
} // xos
